package org.dromara.web.modbus.service;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.system.domain.VariableAssociation;
import org.dromara.system.service.ISensorBackUpService;
import org.dromara.system.service.ISensorService;
import org.dromara.system.service.IVariableAssociationService;
import org.dromara.web.modbus.utils.RotatingUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.TimeUnit;

@Service
@Slf4j
@RequiredArgsConstructor
public class RotatingService {

    private final IVariableAssociationService variableAssociationService;
    private final ISensorService sensorService;

    private final ISensorBackUpService sensorBackUpService;

    public void batchReadConcurrently(int batchSize, int threadCount) {
        List<VariableAssociation> variableAssociations = variableAssociationService.getVariableAssociationByIdAndSource(5);

        ForkJoinPool customThreadPool = new ForkJoinPool(threadCount);
        try {
            List<CompletableFuture<Void>> futures = new ArrayList<>();

            for (int i = 0; i < variableAssociations.size(); i += batchSize) {
                int start = i;
                int end = Math.min(i + batchSize, variableAssociations.size());
                List<VariableAssociation> batch = variableAssociations.subList(start, end);

                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                    int maxRetries = 3;
                    for (int retry = 0; retry < maxRetries; retry++) {
                        try {
                            readVariableAssociations(batch);
                            break; // 成功则跳出重试循环
                        } catch (Exception e) {
                            log.error("批次读取失败，重试次数: " + retry, e);
                            if (retry == maxRetries - 1) {
                                throw new RuntimeException("批次读取最终失败", e);
                            }
                        }
                    }
                }, customThreadPool);

                futures.add(future);
            }

            CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

            if (!customThreadPool.awaitTermination(2, TimeUnit.MINUTES)) {
                throw new RuntimeException("任务超时");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("批量读取任务被中断", e);
        } finally {
            customThreadPool.shutdownNow();
        }
    }

    private void readVariableAssociations(List<VariableAssociation> variableAssociations) throws Exception {
        for (VariableAssociation variableAssociation : variableAssociations) {
            Number value = RotatingUtils.batchReadOne(variableAssociation);
            variableAssociationService.updateSensorValue(variableAssociation.getId(), value);
            Float lastValue = sensorService.getLatestValue(variableAssociation.getId());
            if (lastValue == null || !lastValue.equals(value.floatValue())) {
                sensorService.insertData(value.floatValue(), variableAssociation.getId());
                sensorBackUpService.insertData(value.floatValue(), variableAssociation.getId());
            }
            Thread.sleep(100);
        }

    }
}
